import { creepRoleEnum } from "../enum"
import { getCollectPoint, objIDToObj, roomNameToObj } from "./baseTools"
import { deleteCreepToTargetCreepList, pushCreepToTargetCreepList } from "./tools/creepTool"
import { AStarCostPoint } from '../config'

export default {
    init: function (params) {
        let { room } = params
        let roomMemory = room.memory
        // 建筑物
        roomMemory['structure'] = {}
        // creep        
        roomMemory['creeps'] = {}
        // A*寻路
        roomMemory['terrain'] = {}
        // 自动建造模块
        roomMemory['autoBuild'] = {}
        initFormatStructure(room)
        initFormatCreep(room)
        initCostMatrix(room, AStarCostPoint)
    },
    /**数据的初始化是全量的，因此要和init拆分开 */
    initData: function () {
        this.updateData()
        this.deepUpdate()
    },
    /**单独房间内的数据更新
     * 1. 调整到room.checkSelf()里边去
     */
    updateDataByRoom: function (params) {
        let { room, roomName } = params
    },
    /**全量数据更新 */
    updateData: function () {
        updateStructureMemory()
        updateCreepMemory()
    },
    /**深度更新，一些静态数据，或者不常用数据的更新
     * 1. source四周的store以及extension
     */
    deepUpdate: function () {
        Object.keys(Memory.rooms).map(roomName => {
            let roomMemory = Memory.rooms[roomName]
            Object.keys(roomMemory['structure']['source']).map(id => {
                deepUpdateSource(id)
            })
        })
    }

}

// #region 初始化
/**建筑物内存格式初始化 */
function initFormatStructure(room) {
    room = roomNameToObj(room)
    let roomMemory = room.memory
    // 要纳入统计的白名单
    let whiteList = [FIND_SOURCES, FIND_STRUCTURES, FIND_CONSTRUCTION_SITES]
    let objList = []
    whiteList.map(findType => { objList = objList.concat(room.find(findType)) })
    objList.map(obj => initFormatStructureMemory(obj))
}
/**初始化制定建筑内存 */
export function initFormatStructureMemory(obj) {
    obj = objIDToObj(obj)
    let roomMemory = obj.room.memory
    if (!obj || ('progress' in obj && obj.progress != obj.progressTotal && obj.structureType != STRUCTURE_CONTROLLER)) return // 存在进度条，说明是工地
    let objDeta = {
        pos: obj.pos,
        publishTask: [],
        isRuning: false,
        state: {}
    }
    if (!obj.structureType) console.log(`${room.name}房间内存在${obj.name ? obj.name : obj.id}没有structureType属性`);
    if (!roomMemory['structure'][obj.structureType]) roomMemory['structure'][obj.structureType] = {}
    let objMemory = roomMemory['structure'][obj.structureType][obj.id] = objDeta
    if (!objMemory['creeps']) objMemory['creeps'] = []
    // 类似于能源点需要被纳入采集统计的structureType类型建筑
    if (['source'].includes(obj.structureType)) {
        // 关于一些构筑物特化的初始化：source周边的container和extension的更新
        objMemory['collectPoint'] = getCollectPoint(obj.pos)
        objMemory['extensionPoint'] = getCollectPoint(obj.pos, 2, 2)
    }
}
/**creep内存格式初始化 */
function initFormatCreep(room) {
    room = roomNameToObj(room)
    if (!room) return
    let roomMemory = room.memory
    if (!Memory.creeps) Memory.creeps = {}
    Object.keys(creepRoleEnum).map(creepType => {
        roomMemory['creeps'][creepType] = {}
        Object.keys(creepRoleEnum[creepType]).map(creepRole => {
            roomMemory['creeps'][creepType][creepRole] = []
        })
    })
    Object.keys(Memory.creeps).map(creepName => {
        // 一些状态的初始化
        Memory.creeps[creepName].state.sleep = false
    })
}
/**A*寻路CostMatrix初始化 */
function initCostMatrix(room, costPoint) {
    let costMs = new PathFinder.CostMatrix
    // 序列化存储，反序列化使用
    room.memory['terrain']['costMatrix'] = costMs.serialize()
    costMs = PathFinder.CostMatrix.deserialize(room.memory['terrain']['costMatrix'])
    // 更新道路及可踏入的建筑及门洞及不可进入建筑的消耗
    room.find(FIND_STRUCTURES).forEach(structure => {
        // 修改道路上的消耗,不在点数内的则是不可通行建筑
        let costMovePoint = costPoint[structure.structureType]
        if (!costMovePoint) costMovePoint = 0xff
        costMs.set(structure.pos.x, structure.pos.y, costMovePoint)
    })
    // 修改对应坐标的移动消耗
    room.memory['terrain']['costMatrix'] = costMs.serialize()
}
// #endregion

// #region 更新
/**建筑物内存数据更新 */
function updateStructureMemory() {
    Object.keys(Memory.rooms).map(roomName => {
        // 清空建筑数据:1. 挂载的creep，推送的任务
        Object.keys(Memory.rooms[roomName]['structure']).map(structureType => {
            Object.keys(Memory.rooms[roomName]['structure'][structureType]).map(id => {
                let objMemory = Memory.rooms[roomName]['structure'][structureType][id]
                objMemory.creeps = objMemory.creeps.filter(creepName => {
                    // 验证是否存在，且目标列表中是否存在当前obj的ID
                    let creep = Game.creeps[creepName]
                    if (!creep) return false
                    if (creep.memory.targetID.indexOf(id) != -1) return true
                    return false
                })
                objMemory.creeps = [...new Set(objMemory.creeps)]   // 去重
                if (objMemory.publishTask.length != 0) {
                    let publishTaskList = []
                    objMemory.publishTask.map(taskID => { if (Memory.rooms[roomName]['task']['taskDeta'][taskID]) publishTaskList.push(taskID) })
                    objMemory.publishTask = publishTaskList   // 更新发布的任务
                }
            })
        })
        //每个房间的建筑工地,及当前工地的工程量
        updateConstructionSiteBuildAmount(roomName)
    })
}
/**creep内存数据更新
 * 1. 清除死亡creep
 * 2. 更新更新每个房间creep统计表
 * 3. 更新所有挂载目标的creeps挂载统计表
 */
function updateCreepMemory() {
    if (!Memory.creeps) Memory.creeps = {}
    Object.keys(Memory.rooms).map(roomName => initFormatCreep(roomName))
    if (!Memory.creeps) Memory.creeps = {}
    Object.keys(Memory.creeps).map(creepName => {
        checkCreepSelf(creepName)
    })
}
/**A*寻路消耗更新roomName房间对应坐标的移动消耗参数
 * 1. params入参格式一:{pos:{x:15,y:15},cost:2}
 * 2. params入参格式二:[{pos:{x:15,y:15},cost:2},{pos:{x:18,y:17},cost:1}]
 * 3. params入参格式三:{pos:{x:15,y:15},structureType:'road'}
 */
export function updateCostMat(roomName, params) {
    if (!Memory.rooms[roomName]['terrain']) {
        Memory.rooms[roomName]['terrain'] = {}
        let costMs = new PathFinder.CostMatrix
        Memory.rooms[roomName]['terrain']['costMatrix'] = costMs.serialize()
    }
    // 获取自定义路径数据
    let costMs = PathFinder.CostMatrix.deserialize(Memory.rooms[roomName]['terrain']['costMatrix'])
    // 修改坐标点的消耗的日志信息
    if (Array.isArray(params)) {
        params.forEach(point => costMs.set(point.pos.x, point.pos.y, point.cost))
    } else {
        params.cost ? params.cost = params.cost : params.cost = AStarCostPoint[params.structureType]
        // console.log('更新的坐标' + JSON.stringify(params.pos) + '的寻路消耗,需要' + params.cost + '点移动力');
        costMs.set(params.pos.x, params.pos.y, params.cost)
    }
    // 修改对应坐标的移动消耗
    Memory.rooms[roomName]['terrain']['costMatrix'] = costMs.serialize()
}
/**检查creep自身的内存数据状况
 * 1. 是否已经死亡,死亡则清楚归属的数据：包括内存，挂载的任务修改为原状态
 */
export function checkCreepSelf(creepName) {
    let creep = Game.creeps[creepName]
    if (!creep) {
        if (!Memory.creeps[creepName].targetPos) delete Memory.creeps[creepName]
        if (Memory.rooms[Memory.creeps[creepName].targetPos.roomName]) deleteCreepToTargetCreepList(creepName) // 只有当还在房间处于统计表内,清除已死亡creep的内存数据
        delete Memory.creeps[creepName]
        return null
    }
    // 对creep及相关目标的数据更新
    pushCreepToTargetCreepList(creepName)
    // 检查creep挂载的任务是否存在，不存在则删除;ps：会导致在上传代码之后，清空了task中的内存数据，导致creep当前任务找不到对应的任务，但我觉得是必要的
    if (creep.memory.currentTaskID && !Memory.rooms[Memory.creeps[creepName].targetPos.roomName]['task']['taskDeta'][creep.memory.currentTaskID]) {
        delete creep.memory.currentTaskID
    }
    return true
}
/**更新房间内所有建筑工地的工程量 */
export function updateConstructionSiteBuildAmount(roomName) {
    let constructionSites = Game.constructionSites
    let roomSiteIDlist = Object.keys(constructionSites).filter(siteID => constructionSites[siteID].pos.roomName == roomName)
    Memory.rooms[roomName]['autoBuild']['constructionSite'] = roomSiteIDlist
    Memory.rooms[roomName]['autoBuild']['buildAmount'] = roomSiteIDlist.reduce((a, c) => {
        let siteObj = Game.getObjectById(c)
        return a + (siteObj.progressTotal - siteObj.progress)
    }, 0)
}
/**更新指定建筑挂载的creeps是否存在异常 */
export function updateStructureCreepList(obj) {
    obj = objIDToObj(obj)
    if (!obj) return
    let objMemory = obj.room.memory['structure'][obj.structureType][obj.id]
    if (objMemory.creeps.length == 0) return
    objMemory.creeps = objMemory.creeps.filter(creepName => Memory.creeps[creepName].targetID.includes(obj.id))
}
// #endregion

//#region 深度更新
/**更新对应source的extension和container */
export function deepUpdateSource(source) {
    source = objIDToObj(source)
    let sourceMemory = Memory.rooms[source.pos.roomName]['structure']['source'][source.id]
    // 初始化    
    sourceMemory['collectPoint'] = getCollectPoint(source.pos)
    sourceMemory['extensionPoint'] = getCollectPoint(source.pos, 2, 2)
    // 更新container
    sourceMemory.collectPoint.map((pos, index) => {
        let look = source.room.lookAt(pos.x, pos.y)
        look = look.filter(lookObj => lookObj.type == 'structure' && lookObj.structure.structureType == STRUCTURE_CONTAINER)
        if (look.length != 0) {
            // 如果存在正确的建筑，那么就更新对应位置
            look = look[0]['structure']
            sourceMemory['collectPoint'][index].type = look.structureType
            sourceMemory['collectPoint'][index].id = look.id
        }
    })
    // 更新extension
    sourceMemory.extensionPoint.map((pos, index) => {
        let look = source.room.lookAt(pos.x, pos.y)
        look = look.filter(lookObj => lookObj.type == 'structure' && lookObj.structure.structureType == STRUCTURE_EXTENSION)
        if (look.length != 0) {
            // 如果存在正确的建筑，那么就更新对应位置
            look = look[0]['structure']
            sourceMemory['extensionPoint'][index].type = look.structureType
            sourceMemory['extensionPoint'][index].id = look.id
        }
    })

}
//#endregion